﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Collections;

namespace Tools
{
    #region ShallowCloning

    ///// <summary>
    ///// 
    ///// </summary>
    //public static class CloneUtil
    //{     
    //    static Dictionary<Type, Delegate> _cachedIL = new Dictionary<Type, Delegate>();    

    //    /// <summary>
    //    /// ShallowCloning
    //    /// </summary>
    //    /// <typeparam name="T"></typeparam>
    //    /// <param name="myObject"></param>
    //    /// <returns></returns>
    //    public static T ShallowClone<T>(T myObject)    
    //    {         
    //        Delegate myExec = null;          
    //        if (!_cachedIL.TryGetValue(typeof(T), out myExec))         
    //        {             
    //            var dymMethod = new DynamicMethod("DoClone", typeof(T), new Type[] { typeof(T) }, true);             
    //            var cInfo = myObject.GetType().GetConstructor(new Type[] { });              
    //            var generator = dymMethod.GetILGenerator();              
    //            var lbf = generator.DeclareLocal(typeof(T));              
    //            generator.Emit(OpCodes.Newobj, cInfo);             
    //            generator.Emit(OpCodes.Stloc_0);              
    //            foreach (var field in myObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))             
    //            {                 
    //                // Load the new object on the eval stack... (currently 1 item on eval stack)                 
    //                generator.Emit(OpCodes.Ldloc_0);                 
    //                // Load initial object (parameter)          (currently 2 items on eval stack)                 
    //                generator.Emit(OpCodes.Ldarg_0);                 
    //                // Replace value by field value             (still currently 2 items on eval stack)                 
    //                generator.Emit(OpCodes.Ldfld, field);                 
    //                // Store the value of the top on the eval stack into the object underneath that value on the value stack.                 //  (0 items on eval stack)                 
    //                generator.Emit(OpCodes.Stfld, field);            
    //            }              
    //            // Load new constructed obj on eval stack -> 1 item on stack            
    //            generator.Emit(OpCodes.Ldloc_0);             
    //            // Return constructed object.   --> 0 items on stack            
    //            generator.Emit(OpCodes.Ret);              
    //            myExec = dymMethod.CreateDelegate(typeof(Func<T, T>));              
    //            _cachedIL.Add(typeof(T), myExec);        
    //        }          
    //        return ((Func<T, T>)myExec)(myObject);     
    //    }
    //}

    #endregion

    #region 1.1版本，有功能bug

    ////from http://whizzodev.blogspot.com/2008/06/object-deep-cloning-using-il-in-c_20.html 深拷贝功能不正确 2011-05-29

    ///// <summary>
    ///// Enumeration that defines the type of cloning of a field.
    ///// Used in combination with the CloneAttribute
    ///// </summary>
    //public enum CloneType
    //{
    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    None,

    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    ShallowCloning,

    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    DeepCloning
    //}

    ///// <summary>
    ///// CloningAttribute for specifying the cloneproperties of a field.
    ///// </summary>
    //[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
    //public class CloneAttribute : Attribute
    //{
    //    private CloneType _clonetype;

    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    public CloneAttribute()
    //    {

    //    }

    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    public CloneType CloneType
    //    {
    //        get { return _clonetype; }
    //        set { _clonetype = value; }
    //    }
    //}

    ///// <summary>
    ///// Class that clones objects
    ///// </summary>
    ///// <remarks>
    ///// Currently can deepclone to 1 level deep.
    ///// Ex. Person.Addresses (Person.List[Address]) 
    ///// -> Clones 'Person' deep
    ///// -> Clones the objects of the 'Address' list deep
    ///// -> Clones the sub-objects of the Address object shallow. (at the moment)
    ///// </remarks>
    //public static class CloneUtil<T>
    //where T : class
    //{
    //    #region Declarations
    //    // Dictionaries for caching the (pre)compiled generated IL code.
    //    private static Dictionary<Type, Delegate> _cachedILShallow = new Dictionary<Type, Delegate>();
    //    private static Dictionary<Type, Delegate> _cachedILDeep = new Dictionary<Type, Delegate>();
    //    // This is used for setting the fixed cloning, of this is null, then
    //    // the custom cloning should be invoked. (use Clone(T obj) for custom cloning)
    //    private static CloneType? _globalCloneType = CloneType.ShallowCloning;

    //    #endregion

    //    #region Public Methods

    //    /// <summary>
    //    /// Clone an object with Deep Cloning or with a custom strategy 
    //    /// such as ShallowCloning and/or DeepCloning combined (use the CloneAttribute)
    //    /// </summary>
    //    /// <param name="obj">Object to perform cloning on.</param>
    //    /// <returns>Cloned object.</returns>
    //    public static T Clone(T obj)
    //    {
    //        _globalCloneType = null;
    //        return CloneObjectWithILDeep(obj);
    //    }

    //    /// <summary>
    //    /// Clone an object with one strategy (DeepClone or ShallowClone)
    //    /// </summary>
    //    /// <param name="obj">Object to perform cloning on.</param>
    //    /// <param name="cloneType">Type of cloning</param>
    //    /// <returns>Cloned object.</returns>
    //    /// <exception cref="InvalidOperationException">When a wrong enum for cloningtype is passed.</exception>
    //    public static T Clone(T obj, CloneType cloneType)
    //    {
    //        if (_globalCloneType != null)
    //            _globalCloneType = cloneType;
    //        switch (cloneType)
    //        {
    //            case CloneType.None:
    //                throw new InvalidOperationException("No need to call this method?");
    //            case CloneType.ShallowCloning:
    //                return CloneObjectWithILShallow(obj);
    //            case CloneType.DeepCloning:
    //                return CloneObjectWithILDeep(obj);
    //            default:
    //                break;
    //        }
    //        return default(T);
    //    }

    //    #endregion

    //    #region Private Methods

    //    /// <summary>    
    //    /// Generic cloning method that clones an object using IL.    
    //    /// Only the first call of a certain type will hold back performance.    
    //    /// After the first call, the compiled IL is executed.    
    //    /// </summary>    
    //    /// <typeparam name="T">Type of object to clone</typeparam>    
    //    /// <param name="myObject">Object to clone</param>    
    //    /// <returns>Cloned object (shallow)</returns>    
    //    private static T CloneObjectWithILShallow(T myObject)
    //    {
    //        Delegate myExec = null;
    //        if (!_cachedILShallow.TryGetValue(typeof(T), out myExec))
    //        {
    //            DynamicMethod dymMethod = new DynamicMethod("DoShallowClone", typeof(T), new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true);
    //            ConstructorInfo cInfo = myObject.GetType().GetConstructor(new Type[] { });
    //            ILGenerator generator = dymMethod.GetILGenerator();
    //            LocalBuilder lbf = generator.DeclareLocal(typeof(T));
    //            generator.Emit(OpCodes.Newobj, cInfo);
    //            generator.Emit(OpCodes.Stloc_0);
    //            foreach (FieldInfo field in myObject.GetType().GetFields(System.Reflection.BindingFlags.Instance
    //            | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
    //            {
    //                generator.Emit(OpCodes.Ldloc_0);
    //                generator.Emit(OpCodes.Ldarg_0);
    //                generator.Emit(OpCodes.Ldfld, field);
    //                generator.Emit(OpCodes.Stfld, field);
    //            }
    //            generator.Emit(OpCodes.Ldloc_0);
    //            generator.Emit(OpCodes.Ret);
    //            myExec = dymMethod.CreateDelegate(typeof(Func<T, T>));
    //            _cachedILShallow.Add(typeof(T), myExec);
    //        }
    //        return ((Func<T, T>)myExec)(myObject);
    //    }

    //    /// <summary>
    //    /// Generic cloning method that clones an object using IL.
    //    /// Only the first call of a certain type will hold back performance.
    //    /// After the first call, the compiled IL is executed. 
    //    /// </summary>
    //    /// <param name="myObject">Type of object to clone</param>
    //    /// <returns>Cloned object (deeply cloned)</returns>
    //    private static T CloneObjectWithILDeep(T myObject)
    //    {
    //        Delegate myExec = null;
    //        if (!_cachedILDeep.TryGetValue(typeof(T), out myExec))
    //        {
    //            // Create ILGenerator            
    //            DynamicMethod dymMethod = new DynamicMethod("DoDeepClone", typeof(T), new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true);
    //            ILGenerator generator = dymMethod.GetILGenerator();
    //            LocalBuilder cloneVariable = generator.DeclareLocal(myObject.GetType());

    //            ConstructorInfo cInfo = myObject.GetType().GetConstructor(Type.EmptyTypes);
    //            generator.Emit(OpCodes.Newobj, cInfo);
    //            generator.Emit(OpCodes.Stloc, cloneVariable);

    //            foreach (FieldInfo field in typeof(T).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
    //            {
    //                if (_globalCloneType == CloneType.DeepCloning)
    //                {
    //                    if (field.FieldType.IsValueType || field.FieldType == typeof(string))
    //                    {
    //                        generator.Emit(OpCodes.Ldloc, cloneVariable);
    //                        generator.Emit(OpCodes.Ldarg_0);
    //                        generator.Emit(OpCodes.Ldfld, field);
    //                        generator.Emit(OpCodes.Stfld, field);
    //                    }
    //                    else if (field.FieldType.IsClass)
    //                    {
    //                        CopyReferenceType(generator, cloneVariable, field);
    //                    }
    //                }
    //                else
    //                {
    //                    switch (GetCloneTypeForField(field))
    //                    {
    //                        case CloneType.ShallowCloning:
    //                            {
    //                                generator.Emit(OpCodes.Ldloc, cloneVariable);
    //                                generator.Emit(OpCodes.Ldarg_0);
    //                                generator.Emit(OpCodes.Ldfld, field);
    //                                generator.Emit(OpCodes.Stfld, field);
    //                                break;
    //                            }
    //                        case CloneType.DeepCloning:
    //                            {
    //                                if (field.FieldType.IsValueType || field.FieldType == typeof(string))
    //                                {
    //                                    generator.Emit(OpCodes.Ldloc, cloneVariable);
    //                                    generator.Emit(OpCodes.Ldarg_0);
    //                                    generator.Emit(OpCodes.Ldfld, field);
    //                                    generator.Emit(OpCodes.Stfld, field);
    //                                }
    //                                else if (field.FieldType.IsClass)
    //                                    CopyReferenceType(generator, cloneVariable, field);
    //                                break;
    //                            }
    //                        case CloneType.None:
    //                            {
    //                                // Do nothing here, field is not cloned.
    //                            }
    //                            break;
    //                    }
    //                }
    //            }
    //            generator.Emit(OpCodes.Ldloc_0);
    //            generator.Emit(OpCodes.Ret);
    //            myExec = dymMethod.CreateDelegate(typeof(Func<T, T>));
    //            _cachedILDeep.Add(typeof(T), myExec);
    //        }
    //        return ((Func<T, T>)myExec)(myObject);
    //    }

    //    /// <summary>
    //    /// Helper method to clone a reference type.
    //    /// This method clones IList and IEnumerables and other reference types (classes)
    //    /// Arrays are not yet supported (ex. string[])
    //    /// </summary>
    //    /// <param name="generator">IL generator to emit code to.</param>
    //    /// <param name="cloneVar">Local store wheren the clone object is located. (or child of)</param>
    //    /// <param name="field">Field definition of the reference type to clone.</param>
    //    private static void CopyReferenceType(ILGenerator generator, LocalBuilder cloneVar, FieldInfo field)
    //    {
    //        if (field.FieldType.IsSubclassOf(typeof(Delegate)))
    //        {
    //            return;
    //        }
    //        LocalBuilder lbTempVar = generator.DeclareLocal(field.FieldType);

    //        if (field.FieldType.GetInterface("IEnumerable") != null && field.FieldType.GetInterface("IList") != null)
    //        {
    //            if (field.FieldType.IsGenericType)
    //            {
    //                Type argumentType = field.FieldType.GetGenericArguments()[0];
    //                Type genericTypeEnum = Type.GetType("System.Collections.Generic.IEnumerable`1[" + argumentType.FullName + "]");

    //                ConstructorInfo ci = field.FieldType.GetConstructor(new Type[] { genericTypeEnum });
    //                if (ci != null && GetCloneTypeForField(field) == CloneType.ShallowCloning)
    //                {
    //                    generator.Emit(OpCodes.Ldarg_0);
    //                    generator.Emit(OpCodes.Ldfld, field);
    //                    generator.Emit(OpCodes.Newobj, ci);
    //                    generator.Emit(OpCodes.Stloc, lbTempVar);
    //                    generator.Emit(OpCodes.Ldloc, cloneVar);
    //                    generator.Emit(OpCodes.Ldloc, lbTempVar);
    //                    generator.Emit(OpCodes.Stfld, field);
    //                }
    //                else
    //                {
    //                    ci = field.FieldType.GetConstructor(Type.EmptyTypes);
    //                    if (ci != null)
    //                    {
    //                        generator.Emit(OpCodes.Newobj, ci);
    //                        generator.Emit(OpCodes.Stloc, lbTempVar);
    //                        generator.Emit(OpCodes.Ldloc, cloneVar);
    //                        generator.Emit(OpCodes.Ldloc, lbTempVar);
    //                        generator.Emit(OpCodes.Stfld, field);
    //                        CloneList(generator, field, argumentType, lbTempVar);
    //                    }
    //                }
    //            }
    //        }
    //        else
    //        {
    //            ConstructorInfo cInfo = field.FieldType.GetConstructor(new Type[] { });
    //            generator.Emit(OpCodes.Newobj, cInfo);
    //            generator.Emit(OpCodes.Stloc, lbTempVar);
    //            generator.Emit(OpCodes.Ldloc, cloneVar);
    //            generator.Emit(OpCodes.Ldloc, lbTempVar);
    //            generator.Emit(OpCodes.Stfld, field);
    //            foreach (FieldInfo fi in field.FieldType.GetFields(System.Reflection.BindingFlags.Instance
    //                | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
    //            {
    //                if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
    //                {
    //                    generator.Emit(OpCodes.Ldloc_1);
    //                    generator.Emit(OpCodes.Ldarg_0);
    //                    generator.Emit(OpCodes.Ldfld, field);
    //                    generator.Emit(OpCodes.Ldfld, fi);
    //                    generator.Emit(OpCodes.Stfld, fi);
    //                }
    //            }
    //        }
    //    }

    //    /// <summary>
    //    /// Makes a deep copy of an IList of IEnumerable
    //    /// Creating new objects of the list and containing objects. (using default constructor)
    //    /// And by invoking the deepclone method defined above. (recursive)
    //    /// </summary>
    //    /// <param name="generator">IL generator to emit code to.</param>
    //    /// <param name="listField">Field definition of the reference type of the list to clone.</param>
    //    /// <param name="typeToClone">Base-type to clone (argument of List<T></param>
    //    /// <param name="cloneVar">Local store wheren the clone object is located. (or child of)</param>
    //    private static void CloneList(ILGenerator generator, FieldInfo listField, Type typeToClone, LocalBuilder cloneVar)
    //    {
    //        Type genIEnumeratorTyp = Type.GetType("System.Collections.Generic.IEnumerator`1[" + typeToClone.FullName + "]");
    //        Type genIEnumeratorTypLocal = Type.GetType(listField.FieldType.Namespace + "." + listField.FieldType.Name + "+Enumerator[[" + typeToClone.FullName + "]]");
    //        LocalBuilder lbEnumObject = generator.DeclareLocal(genIEnumeratorTyp);
    //        LocalBuilder lbCheckStatement = generator.DeclareLocal(typeof(bool));
    //        Label checkOfWhile = generator.DefineLabel();
    //        Label startOfWhile = generator.DefineLabel();
    //        MethodInfo miEnumerator = listField.FieldType.GetMethod("GetEnumerator");
    //        generator.Emit(OpCodes.Ldarg_0);
    //        generator.Emit(OpCodes.Ldfld, listField);
    //        generator.Emit(OpCodes.Callvirt, miEnumerator);
    //        if (genIEnumeratorTypLocal != null)
    //        {
    //            generator.Emit(OpCodes.Box, genIEnumeratorTypLocal);
    //        }
    //        generator.Emit(OpCodes.Stloc, lbEnumObject);
    //        generator.Emit(OpCodes.Br_S, checkOfWhile);
    //        generator.MarkLabel(startOfWhile);
    //        generator.Emit(OpCodes.Nop);
    //        generator.Emit(OpCodes.Ldloc, cloneVar);
    //        generator.Emit(OpCodes.Ldloc, lbEnumObject);
    //        MethodInfo miCurrent = genIEnumeratorTyp.GetProperty("Current").GetGetMethod();
    //        generator.Emit(OpCodes.Callvirt, miCurrent);
    //        Type cloneHelper = Type.GetType(typeof(CloneUtil<T>).Namespace + "." + typeof(CloneUtil<T>).Name + "[" + miCurrent.ReturnType.FullName + "]");
    //        MethodInfo miDeepClone = cloneHelper.GetMethod("CloneObjectWithILDeep", BindingFlags.Static | BindingFlags.NonPublic);
    //        generator.Emit(OpCodes.Call, miDeepClone);
    //        MethodInfo miAdd = listField.FieldType.GetMethod("Add");
    //        generator.Emit(OpCodes.Callvirt, miAdd);
    //        generator.Emit(OpCodes.Nop);
    //        generator.MarkLabel(checkOfWhile);
    //        generator.Emit(OpCodes.Nop);
    //        generator.Emit(OpCodes.Ldloc, lbEnumObject);
    //        MethodInfo miMoveNext = typeof(IEnumerator).GetMethod("MoveNext");
    //        generator.Emit(OpCodes.Callvirt, miMoveNext);
    //        generator.Emit(OpCodes.Stloc, lbCheckStatement);
    //        generator.Emit(OpCodes.Ldloc, lbCheckStatement);
    //        generator.Emit(OpCodes.Brtrue_S, startOfWhile);
    //    }

    //    /// <summary>
    //    /// Returns the type of cloning to apply on a certain field when in custom mode.
    //    /// Otherwise the main cloning method is returned.
    //    /// You can invoke custom mode by invoking the method Clone(T obj)
    //    /// </summary>
    //    /// <param name="field">Field to examine</param>
    //    /// <returns>Type of cloning to use for this field.</returns>
    //    private static CloneType GetCloneTypeForField(FieldInfo field)
    //    {
    //        object[] attributes = field.GetCustomAttributes(typeof(CloneAttribute), true);
    //        if (attributes == null || attributes.Length == 0)
    //        {
    //            if (!_globalCloneType.HasValue)
    //                return CloneType.ShallowCloning;
    //            else
    //                return _globalCloneType.Value;
    //        }
    //        return (attributes[0] as CloneAttribute).CloneType;
    //    }

    //    #endregion
    //}

    #endregion

    //from http://whizzodev.blogspot.com/2008/06/object-deep-cloning-using-il-in-c.html
    //复杂对象执行1W次大约1081ms 

    /// <summary>    
    /// Delegate handler that's used to compile the IL to.    
    /// (This delegate is standard in .net 3.5)    
    /// </summary>    
    /// <typeparam name="T1">Parameter Type</typeparam>    
    /// <typeparam name="TResult">Return Type</typeparam>    
    /// <param name="arg1">Argument</param>    
    /// <returns>Result</returns>    
    public delegate TResult Func<T1, TResult>(T1 arg1);

    /// <summary>
    /// 深度拷贝，使用方法：newObj = new CloneUtil().CloneObjectWithILDeep[H](h);
    /// </summary>
    public class CloneUtil
    {
        /// <summary>    
        /// This dictionary caches the delegates for each 'to-clone' type.    
        /// </summary>    
        private static Dictionary<Type, Delegate> _cachedIL = new Dictionary<Type, Delegate>();

        private static Dictionary<Type, Delegate> _cachedILDeep = new Dictionary<Type, Delegate>();
        private static LocalBuilder _lbfTemp;

        /// <summary>
        /// ShallowCloning
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="myObject"></param>
        /// <returns></returns>
        public static T ShallowClone<T>(T myObject)
        {
            Delegate myExec = null;
            if (!_cachedIL.TryGetValue(typeof(T), out myExec))
            {
                var dymMethod = new DynamicMethod("DoClone", typeof(T), new Type[] { typeof(T) }, true);
                var cInfo = myObject.GetType().GetConstructor(new Type[] { });
                var generator = dymMethod.GetILGenerator();
                var lbf = generator.DeclareLocal(typeof(T));
                generator.Emit(OpCodes.Newobj, cInfo);
                generator.Emit(OpCodes.Stloc_0);
                foreach (var field in myObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    // Load the new object on the eval stack... (currently 1 item on eval stack)                 
                    generator.Emit(OpCodes.Ldloc_0);
                    // Load initial object (parameter)          (currently 2 items on eval stack)                 
                    generator.Emit(OpCodes.Ldarg_0);
                    // Replace value by field value             (still currently 2 items on eval stack)                 
                    generator.Emit(OpCodes.Ldfld, field);
                    // Store the value of the top on the eval stack into the object underneath that value on the value stack.                 //  (0 items on eval stack)                 
                    generator.Emit(OpCodes.Stfld, field);
                }
                // Load new constructed obj on eval stack -> 1 item on stack            
                generator.Emit(OpCodes.Ldloc_0);
                // Return constructed object.   --> 0 items on stack            
                generator.Emit(OpCodes.Ret);
                myExec = dymMethod.CreateDelegate(typeof(Func<T, T>));
                _cachedIL.Add(typeof(T), myExec);
            }
            return ((Func<T, T>)myExec)(myObject);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="myObject"></param>
        /// <returns></returns>
        public static T /*CloneObjectWithILDeep*/DeepClone<T>(T myObject)
        {
            Delegate myExec = null;
            if (!_cachedILDeep.TryGetValue(typeof(T), out myExec))
            {
                // Create ILGenerator (both DM declarations work)
                // DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T), 
                //      new Type[] { typeof(T) }, true);
                DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T),
                    new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true);
                ConstructorInfo cInfo = myObject.GetType().GetConstructor(new Type[] { });
                ILGenerator generator = dymMethod.GetILGenerator();
                LocalBuilder lbf = generator.DeclareLocal(typeof(T));
                generator.Emit(OpCodes.Newobj, cInfo);
                generator.Emit(OpCodes.Stloc_0);

                foreach (FieldInfo field in typeof(T).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
                {
                    if (field.FieldType.IsValueType || field.FieldType == typeof(string))
                        CopyValueType(generator, field);
                    else if (field.FieldType.IsClass)
                        CopyReferenceType(generator, field);
                }
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ret);
                myExec = dymMethod.CreateDelegate(typeof(Func<T, T>));
                _cachedILDeep.Add(typeof(T), myExec);
            }
            return ((Func<T, T>)myExec)(myObject);
        }

        private static void CreateNewTempObject(ILGenerator generator, Type type)
        {
            ConstructorInfo cInfo = type.GetConstructor(new Type[] { });
            generator.Emit(OpCodes.Newobj, cInfo);
            generator.Emit(OpCodes.Stloc, _lbfTemp);
        }

        private static void CopyValueType(ILGenerator generator, FieldInfo field)
        {
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, field);
            generator.Emit(OpCodes.Stfld, field);
        }

        private static void CopyValueTypeTemp(ILGenerator generator, FieldInfo fieldParent, FieldInfo fieldDetail)
        {
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, fieldParent);
            generator.Emit(OpCodes.Ldfld, fieldDetail);
            generator.Emit(OpCodes.Stfld, fieldDetail);
        }

        private static void PlaceNewTempObjInClone(ILGenerator generator, FieldInfo field)
        {
            // Get object from custom location and store it in right field of location 0
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldloc, _lbfTemp);
            generator.Emit(OpCodes.Stfld, field);
        }

        private static void CopyReferenceType(ILGenerator generator, FieldInfo field)
        {
            // We have a reference type.
            _lbfTemp = generator.DeclareLocal(field.FieldType);
            if (field.FieldType.GetInterface("IEnumerable") != null)
            {
                // We have a list type (generic).
                if (field.FieldType.IsGenericType)
                {
                    // Get argument of list type
                    Type argType = field.FieldType.GetGenericArguments()[0];
                    // Check that it has a constructor that accepts another IEnumerable.
                    Type genericType = Type.GetType("System.Collections.Generic.IEnumerable`1["
                            + argType.FullName + "]");

                    ConstructorInfo ci = field.FieldType.GetConstructor(new Type[] { genericType });
                    if (ci != null)
                    {
                        // It has! (Like the List<> class)
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldfld, field);
                        generator.Emit(OpCodes.Newobj, ci);
                        generator.Emit(OpCodes.Stloc, _lbfTemp);
                        PlaceNewTempObjInClone(generator, field);
                    }
                }
            }
            else
            {
                CreateNewTempObject(generator, field.FieldType);
                PlaceNewTempObjInClone(generator, field);
                foreach (FieldInfo fi in field.FieldType.GetFields(System.Reflection.BindingFlags.Instance
                    | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
                {
                    if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
                        CopyValueTypeTemp(generator, field, fi);
                    else if (fi.FieldType.IsClass)
                        CopyReferenceType(generator, fi);
                }
            }
        }
    }

    /*
     Explanation: 

As you see in the code, the model is a little bit expanded. 
But if you shuffle a bit with the code, then you can put it in 1 method again, 
I only did this to improve readability, so that you can understand what's happening, and how the code is generated. 

I also left out the comments from the IL parts, if you want to know what those statements mean, then look at my other post regarding IL cloning (Object cloning using IL in C#), it's explained there. 

Method list of cloning class with a short description: 




Person CloneObjectWithReflection(Person p) 
This method clones an object using reflection (very slow). 


Person CloneNormal(Person p) 
This method clones the person class manually. 
I think a lot of people will do/user this method :) 


T CloneObjectWithILShallow(T myObject) 
Make a shallow copy of an object using IL in a generic method. 


T CloneObjectWithILDeep(T myObject) 
Make a deep copy of an object using IL in a generic method. 


void CreateNewTempObject(ILGenerator generator, Type type) 
Generate IL-code to create a new object of a certain type and store it in a local store. (local variable) 


void CopyValueType(ILGenerator generator, FieldInfo field) 
Generate IL-code to copy the values of a value type to the clone. 


void CopyValueTypeTemp(ILGenerator generator, FieldInfo fieldParent, FieldInfo fieldDetail) 
Generate IL-code to copy the values of a value type from a store location to the destination address in the clone. 


void PlaceNewTempObjInClone(ILGenerator generator, FieldInfo field) 
Generate IL-code to reference an object from a store to an address in the clone. 


void CopyReferenceType(ILGenerator generator, FieldInfo field) 
Generate IL-code to copy the values of a reference type (class) to the clone. Instantiate new objects if needed. 


     */
}
